/*
 * Ganesa Copyright (C) 2008 Wim Crols <twimpiex@gnx.be>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 3
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package be.gnx.ganesa.statistics;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map.Entry;
import java.util.zip.GZIPInputStream;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class Statistics {

  private long numberOfNodes = 0;
  private long numberOfWays = 0;
  private long numberOfRelations = 0;

  private Hashtable<Tag, Integer> nodesTags = new Hashtable<Tag, Integer>();
  private Hashtable<Tag, Integer> waysTags = new Hashtable<Tag, Integer>();
  private Hashtable<Tag, Integer> relationsTags = new Hashtable<Tag, Integer>();

  private class Tag {
    private String key;
    private String value;

    public Tag(String key, String value) {
      this.key = key;
      this.value = value;
    }

    public String getKey() {
      return key;
    }

    public void setKey(String key) {
      this.key = key;
    }

    public String getValue() {
      return value;
    }

    public void setValue(String value) {
      this.value = value;
    }

    @Override
    public boolean equals(Object object) {
      if ((object != null) && (object instanceof Tag)) {
        if (object == this) {
          return true;
        } else if (this.key.equals(((Tag)object).getKey()) && this.value.equals(((Tag)object).getValue())) {
          return true;
        } else {
          return false;
        }
      } else {
        return super.equals(object);
      }
    }

    @Override
    public int hashCode() {
      return key.hashCode() + value.hashCode();
    }

  }

  public Statistics() {

  }

  public void compute() {
    try {
      InputStream inputStream = new GZIPInputStream(new FileInputStream(
          new File("/home/wimc/planet-latest.osm.gz")));
      SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
      parser.parse(inputStream, new DefaultHandler() {
        private boolean node = false;
        private boolean way = false;
        private boolean relation = false;
        private List<Tag> tags = new ArrayList<Tag>();

        @Override
        public void startElement(String uri, String localName, String name,
            Attributes attributes) throws SAXException {
          if (name.equals("node")) {
            node = true;
            tags.clear();
            numberOfNodes++;
            // long id = Long.parseLong(attributes.getValue("id"));
            // BigDecimal lat = new BigDecimal(attributes.getValue("lat"));
            // BigDecimal lon = new BigDecimal(attributes.getValue("lon"));
          }
          if (name.equals("way")) {
            way = true;
            tags.clear();
            numberOfWays++;
            // long id = Long.parseLong(attributes.getValue("id"));
          }
          if (name.equals("relation")) {
            relation = true;
            tags.clear();
            numberOfRelations++;
            // long id = Long.parseLong(attributes.getValue("id"));
          }
          if (name.equals("nd")) {
          }
          if (name.equals("tag")) {
            String key = attributes.getValue("k");
            String value = attributes.getValue("v");
            tags.add(new Tag(key, value));
          }
          super.startElement(uri, localName, name, attributes);
        }

        @Override
        public void endElement(String uri, String localName, String qName)
            throws SAXException {
          if (qName.equals("node")) {
            node = false;
            computeNodeTags(tags);
            if ((numberOfNodes % 500000) == 0) {
              log();
            }
          }
          if (qName.equals("way")) {
            way = false;
            computeWayTags(tags);
            if ((numberOfWays % 500000) == 0) {
              log();
            }
          }
          if (qName.equals("relation")) {
            relation = false;
            computeRelationTags(tags);
            if ((numberOfRelations % 500000) == 0) {
              log();
            }
          }
          if (qName.equals("nd")) {
          }
          if (qName.equals("tag")) {
          }
          super.endElement(uri, localName, qName);
        }

      });
    } catch (IOException ioException) {
      System.err.println(ioException);
    } catch (SAXException saxException) {
      System.err.println(saxException);
    } catch (ParserConfigurationException parserConfigurationException) {
      System.err.println(parserConfigurationException);
    }
  }

  public void computeNodeTags(List<Tag> tags) {
    for (Tag tag : tags) {
      if (nodesTags.get(tag) == null) {
        nodesTags.put(tag, 1);
      } else {
        nodesTags.put(tag, nodesTags.get(tag) + 1);
      }
    }
  }

  public void computeWayTags(List<Tag> tags) {
    for (Tag tag : tags) {
      if (waysTags.get(tag) == null) {
        waysTags.put(tag, 1);
      } else {
        waysTags.put(tag, waysTags.get(tag) + 1);
      }
    }
  }

  public void computeRelationTags(List<Tag> tags) {
    for (Tag tag : tags) {
      if (relationsTags.get(tag) == null) {
        relationsTags.put(tag, 1);
      } else {
        relationsTags.put(tag, relationsTags.get(tag) + 1);
      }
    }
  }

  public void log() {
    System.err.println("number of nodes = " + numberOfNodes);
    for (Entry<Tag, Integer> tag : nodesTags.entrySet()) {
      if (numberOfNodes / tag.getValue() < 100) {
        System.err.println("\t" + tag.getKey().getKey() + "\t" + tag.getKey().getValue()
            + "\t" + tag.getValue());
      }
    }
    System.err.println("number of ways = " + numberOfWays);
    for (Entry<Tag, Integer> tag : waysTags.entrySet()) {
      if (numberOfWays / tag.getValue() < 100) {
        System.err.println("\t" + tag.getKey().getKey() + "\t" + tag.getKey().getValue()
            + "\t" + tag.getValue());
      }
    }
    System.err.println("number of relations = " + numberOfRelations);
    for (Entry<Tag, Integer> tag : relationsTags.entrySet()) {
      if (numberOfRelations / tag.getValue() < 100) {
        System.err.println("\t" + tag.getKey().getKey() + "\t" + tag.getKey().getValue()
            + "\t" + tag.getValue());
      }
    }
  }

  /**
   * @param args
   */
  public static void main(String[] args) {
    Statistics statistics = new Statistics();
    statistics.compute();
    statistics.log();
  }

}
